QR コードスキャンライブラリ @yudiel/react-qr-scanner で IScannerComponents を設定してスキャン時の UI をカスタマイズしてみた

QR コードスキャンライブラリ @yudiel/react-qr-scanner で IScannerComponents を設定してスキャン時の UI をカスタマイズしてみた

Clock Icon2024.09.16

こんにちは、製造ビジネステクノロジー部の若槻です。

以前のエントリで、マイクロ QR コードおよび rMQR コードに対応した QR スキャナーライブラリである yudielcurbelo/react-qr-scanner の Next.js での実装方法をご紹介しました。

https://dev.classmethod.jp/articles/qr-rmqr-qr-next-js

この yudielcurbelo/react-qr-scanner では、IScannerComponents というプロパティを設定することによりスキャン時の UI をカスタマイズすることができます。今回はこちらを実際に試してみます。

ちなみに IScannerComponents をカスタマイズした実装は公式の Stroybook でも公開されておりどなたでも試すことができます。

https://yudielcurbelo.github.io/react-qr-scanner/?path=/story/scanner--scanner

試してみた

スキャナー画面の実装

スキャナー画面の実装は以下の通りです。Scanner 要素で components プロパティにより IScannerComponents を設定しています。Next.js の環境周りは前回の実装を踏襲しています。

sample-next-app/src/app/page.tsx
'use client';

import React, { useState } from 'react';
import { Scanner, IDetectedBarcode } from '@yudiel/react-qr-scanner';

const Home = () => {
  const [scanResult, setScanResult] = useState({ format: '', rawValue: '' });

  const handleScan = (results: IDetectedBarcode[]) => {
    if (results.length > 0) {
      setScanResult({
        format: results[0].format,
        rawValue: results[0].rawValue,
      });
    }
  };

  // コード検出時のカスタムトラッカー
  const customTracker = (
    detectedCodes: IDetectedBarcode[],
    ctx: CanvasRenderingContext2D
  ) => {
    detectedCodes.forEach((code) => {
      // 検出されたコードの周りに赤い枠を描画
      ctx.strokeStyle = 'red';
      ctx.lineWidth = 2;
      ctx.strokeRect(
        code.boundingBox.x,
        code.boundingBox.y,
        code.boundingBox.width,
        code.boundingBox.height
      );

      // コードの内容を表示
      ctx.fillStyle = 'white';
      ctx.fillRect(
        code.boundingBox.x,
        code.boundingBox.y + code.boundingBox.height,
        code.boundingBox.width,
        20
      );
      ctx.fillStyle = 'black';
      ctx.fillText(
        code.rawValue,
        code.boundingBox.x,
        code.boundingBox.y + code.boundingBox.height + 15
      );
    });
  };

  return (
    <div className='h-screen flex flex-col items-center'>
      <h1>QR コードをスキャンしてください</h1>
      <div className='w-[300px]'>
        <Scanner
          onScan={handleScan}
          formats={[
            'qr_code', // QR コード
            'micro_qr_code', // マイクロ QR
          ]}
          allowMultiple={true} // これを指定すると連続でスキャンできる
          // スキャン時の UI をカスタマイズ
          components={{
            tracker: customTracker, // コード検出時の視覚的なフィードバックをカスタマイズ
            audio: true, // スキャン時に音を鳴らす (default: true)
            onOff: true, // スキャンのオンオフを切り替えるボタンを表示する (default: false)
            zoom: true, // ズーム機能を有効にする (default: false)
            finder: false, // ファインダーを表示する (default: true)
            torch: true, // フラッシュライトを有効にする (default: false)
          }}
        />
      </div>
      {scanResult.rawValue && (
        <div className='mt-4 p-2 border border-gray-300 rounded'>
          <p>
            <strong>フォーマット:</strong> {scanResult.format}
          </p>
          <p>
            <strong>内容:</strong> {scanResult.rawValue}
          </p>
        </div>
      )}
    </div>
  );
};

export default Home;

ローカル PC 上での動作確認

前述のアプリケーションを localhost で起動してローカル PC 上で動作を確認してみます。

npm run dev

下記はスキャナーで QR コードをスキャンした際の画面です。

ローカル PC 上で確認した項目は下記となります。

  • tracker に設定したカスタムトラッカーにより、カメラの映像内に検出された QR コードに対するトラッカーが表示されています。
  • audio を無効にしたことにより、スキャン時の「ピッ」という音が鳴らなくなりました。
  • finder を無効にしたことにより、カメラの映像内にファインダー(赤枠)が表示されなくなりました。

ここで注意点として、finder を無効にすると onOff、zoom、torch の機能は表示されなくなります。また zoom、torch はスマートフォン上でのみ利用可能な機能です。これら機能は finder を有効にした上でスマートフォン上で動作確認を行ってみます。

Next.js アプリケーションを AWS にデプロイ

下記の AWS CDK コードで先程の Next.js アプリケーションを AWS にデプロイしてスマートフォンから接続可能とします。

lib/cdk-sample-stack.ts
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3_deployment from 'aws-cdk-lib/aws-s3-deployment';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as cloudfront_origins from 'aws-cdk-lib/aws-cloudfront-origins';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // S3 バケットの作成
    const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });

    // リクエスト URL に index.html を自動追加する CloudFront Function の作成
    const cloudFrontFunction = new cloudfront.Function(
      this,
      'AddSecurityHeadersToTheResponseFunction',
      {
        code: cloudfront.FunctionCode.fromFile({
          filePath: 'src/add-index-html-to-request-url/index.js',
        }),
        // JavaScript runtime 2.0 を指定
        runtime: cloudfront.FunctionRuntime.JS_2_0,
      }
    );

    // CloudFront Destribution を作成
    const distribution = new cloudfront.Distribution(this, 'Distribution', {
      defaultBehavior: {
        origin:
          cloudfront_origins.S3BucketOrigin.withOriginAccessControl(
            websiteBucket
          ),
        // CloudFront Function と Distribution の関連付け
        functionAssociations: [
          {
            function: cloudFrontFunction,
            eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
          },
        ],
      },
      errorResponses: [
        {
          ttl: cdk.Duration.minutes(5),
          httpStatus: 404,
          responseHttpStatus: 404,
          responsePagePath: '/404.html',
        },
      ],
    });

    // CloudFront Distribution のドメイン名を出力
    new cdk.CfnOutput(this, 'DistributionUrl', {
      value: `https://${distribution.distributionDomainName}`,
    });

    // S3 バケットへのコンテンツのデプロイ、CloudFront Distribution のキャッシュ削除
    new s3_deployment.BucketDeployment(this, 'WebsiteDeploy', {
      distribution,
      destinationBucket: websiteBucket,
      distributionPaths: ['/*'],
      sources: [s3_deployment.Source.asset('./sample-next-app/out')], // Next.js のビルド生成物の出力パスを指定
    });
  }
}

上記の実装は下記を参考にしているので、詳細はそちらをご参照ください。

https://dev.classmethod.jp/articles/aws-cdk-cloudfront-functions-request-url-index-html-addition-in-nextjs-application/
https://dev.classmethod.jp/articles/aws-cdk-enables-oac-configuration-on-cloudfront-distribution-with-l2-construct/

npm run build で作成したビルド生成物を S3 バケットにデプロイし、CloudFront Distribution で配信可能とします。

スマートフォンでの動作確認

デプロイされたアプリケーションにスマートフォンからアクセスした様子です。ファインダー右側に表示されているボタンを押すことで onOff、zoom、torch の機能を利用できます。

一番上のボタンを押すことで zoom の機能によりズームインをした様子です。

上から二番目のボタンを押すことでズームアウトをした様子です。

ズームアウトおよびズームインはそれぞれ二段階まで可能です。

上から三番目のボタンを押すことで onOff の機能によりスキャンのオンオフを切り替えることができます。スキャンをオフにするとカメラの映像が停止し、他の機能のボタンも非表示となります。再度ボタンを押すことでスキャンを再開できます。

一番下のボタンを押すことで torch の機能により、分かりづらいですがフラッシュライトを点灯した様子です。再度ボタンを押すことでフラッシュライトを消灯できます。

おわりに

QR コードスキャンライブラリ @yudiel/react-qr-scanner で IScannerComponents を設定してスキャン時の UI をカスタマイズしてみました。

比較的マイナーなライブラリではあるのですが、スキャン可能な QR フォーマット以外のカスタマイズ性もある程度充実しているなと感じました。React の QR コードスキャン機能が必要な場面でぜひ選択肢の一つとして検討してみてください。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.